package com.free.semantic.model.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 命令行执行工具类
 */
public class CommandExecutor {

    /**
     * 执行命令行命令，同步等待结果
     *
     * @param command 要执行的命令
     * @return 命令执行结果，包含退出码、标准输出和错误输出
     */
    public static CommandResult executeCommand(String command) {
        return executeCommand(command, null);
    }

    /**
     * 在指定工作目录执行命令行命令，同步等待结果
     *
     * @param command 要执行的命令
     * @param workingDir 工作目录，如果为null则使用当前目录
     * @return 命令执行结果，包含退出码、标准输出和错误输出
     */
    public static CommandResult executeCommand(String command, String workingDir) {
        try {
            ProcessBuilder processBuilder = new ProcessBuilder();
            
            // 根据操作系统设置命令
            if (System.getProperty("os.name").toLowerCase().contains("windows")) {
                processBuilder.command("cmd.exe", "/c", command);
            } else {
                processBuilder.command("sh", "-c", command);
            }
            
            // 设置工作目录
            if (workingDir != null && !workingDir.isEmpty()) {
                processBuilder.directory(new java.io.File(workingDir));
            }
            
            // 合并错误流和标准输出流
            processBuilder.redirectErrorStream(true);
            
            Process process = processBuilder.start();
            
            // 读取输出
            List<String> output = new ArrayList<>();
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    output.add(line);
                }
            }
            
            // 等待进程完成
            int exitCode = process.waitFor();
            
            return new CommandResult(exitCode, output);
            
        } catch (IOException | InterruptedException e) {
            List<String> errorList = new ArrayList<>();
            errorList.add("执行命令出错: " + e.getMessage());
            return new CommandResult(-1, errorList);
        }
    }
    
    /**
     * 异步执行命令行命令
     *
     * @param command 要执行的命令
     * @return 包含命令执行结果的CompletableFuture
     */
    public static CompletableFuture<CommandResult> executeCommandAsync(String command) {
        return executeCommandAsync(command, null);
    }
    
    /**
     * 在指定工作目录异步执行命令行命令
     *
     * @param command 要执行的命令
     * @param workingDir 工作目录，如果为null则使用当前目录
     * @return 包含命令执行结果的CompletableFuture
     */
    public static CompletableFuture<CommandResult> executeCommandAsync(String command, String workingDir) {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        return CompletableFuture.supplyAsync(() -> executeCommand(command, workingDir), executor)
                .whenComplete((result, throwable) -> executor.shutdown());
    }
    
    /**
     * 执行脚本文件
     *
     * @param scriptPath 脚本文件路径
     * @return 命令执行结果
     */
    public static CommandResult executeScript(String scriptPath) {
        return executeScript(scriptPath, null);
    }
    
    /**
     * 在指定工作目录执行脚本文件
     *
     * @param scriptPath 脚本文件路径
     * @param workingDir 工作目录，如果为null则使用当前目录
     * @return 命令执行结果
     */
    public static CommandResult executeScript(String scriptPath, String workingDir) {
        try {
            // 确保脚本文件存在
            Path path = Paths.get(scriptPath);
            if (!Files.exists(path)) {
                List<String> errorList = new ArrayList<>();
                errorList.add("脚本文件不存在: " + scriptPath);
                return new CommandResult(-1, errorList);
            }
            
            // 确保脚本有执行权限（在类Unix系统上）
            if (!System.getProperty("os.name").toLowerCase().contains("windows")) {
                path.toFile().setExecutable(true);
            }
            
            // 执行脚本
            String command;
            if (System.getProperty("os.name").toLowerCase().contains("windows")) {
                command = scriptPath;
            } else {
                command = "sh " + scriptPath;
            }
            
            return executeCommand(command, workingDir);
            
        } catch (Exception e) {
            return new CommandResult(-1, Collections.singletonList("执行脚本出错: " + e.getMessage()));
        }
    }
    
    /**return new CommandResult(-1, Collections.singletonList("执行脚本出错: " + e.getMessage()));

     * 将脚本内容写入临时文件并执行
     *
     * @param scriptContent 脚本内容
     * @param fileExtension 文件扩展名（如 ".sh", ".bat"）
     * @return 命令执行结果
     */
    public static CommandResult executeScriptContent(String scriptContent, String fileExtension) {
        return executeScriptContent(scriptContent, fileExtension, null);
    }
    
    /**
     * 将脚本内容写入临时文件并在指定工作目录执行
     *
     * @param scriptContent 脚本内容
     * @param fileExtension 文件扩展名（如 ".sh", ".bat"）
     * @param workingDir 工作目录，如果为null则使用当前目录
     * @return 命令执行结果
     */
    public static CommandResult executeScriptContent(String scriptContent, String fileExtension, String workingDir) {
        Path tempScript = null;
        try {
            // 创建临时脚本文件
            tempScript = Files.createTempFile("script_", fileExtension);
            Files.write(tempScript, scriptContent.getBytes(StandardCharsets.UTF_8));
            
            // 设置执行权限（在类Unix系统上）
            if (!System.getProperty("os.name").toLowerCase().contains("windows")) {
                tempScript.toFile().setExecutable(true);
            }
            
            // 执行脚本
            return executeScript(tempScript.toString(), workingDir);
            
        } catch (IOException e) {
            List<String> errorList = new ArrayList<>();
            errorList.add("创建或执行临时脚本出错: " + e.getMessage());
            return new CommandResult(-1, errorList);
        } finally {
            // 清理临时文件
            if (tempScript != null) {
                try {
                    Files.deleteIfExists(tempScript);
                } catch (IOException e) {
                    // 忽略删除临时文件时的错误
                }
            }
        }
    }
    
    /**
     * 命令执行结果类
     */
    public static class CommandResult {
        private final int exitCode;
        private final List<String> output;
        
        public CommandResult(int exitCode, List<String> output) {
            this.exitCode = exitCode;
            this.output = output;
        }
        
        /**
         * 获取命令退出码
         * @return 退出码，0表示成功
         */
        public int getExitCode() {
            return exitCode;
        }
        
        /**
         * 获取命令输出（包含标准输出和错误输出）
         * @return 输出行列表
         */
        public List<String> getOutput() {
            return output;
        }
        
        /**
         * 检查命令是否成功执行
         * @return 如果退出码为0则返回true
         */
        public boolean isSuccess() {
            return exitCode == 0;
        }
        
        /**
         * 获取所有输出作为单个字符串
         * @return 合并后的输出字符串
         */
        public String getOutputString() {
            return String.join(System.lineSeparator(), output);
        }
        
        @Override
        public String toString() {
            return "CommandResult{" +
                    "exitCode=" + exitCode +
                    ", output=" + output +
                    '}';
        }
    }
}
